package com.zl.protocol;

import com.zl.protocol.des.DesHelperV2;
import com.zl.protocol.des.byteUtils;
import com.zl.protocol.time.TimeFormat;
import com.zl.protocol.time.TimeUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @author chenzy
 * @since 2024/9/2
 **/
public class Main {
    public static void main(String[] args) {
//        55A208A001000000000079E491D35CB5F61000DC
        exec("55A208A001001E46E24AC4854EE8792CB0B38A13");
    }

    public static void exec(String qrCodeFromMachine) {
        var reuslt = analysis(qrCodeFromMachine);
        var machineId = (String) reuslt.get("machineId");
        /*处理上次充值结果..*/
        System.out.println("解析上笔充值结果" + reuslt);
        /*本次充值订单处理*/
        var orderTime = System.currentTimeMillis();
        /*本次充值用户id*/
        var userIdHex = "123A";
        /*充值时间*/
        var time = orderTime;
        /*充值金额：100的倍数：100到20000*/
        var num = 200;
        var qrCodeSendToMachine = get(qrCodeFromMachine, machineId, userIdHex, time, num);
        System.out.println("充值二维码:" + qrCodeSendToMachine);
    }

    public final Byte startByte = 0x55;

    public static Map<String, Object> analysis(String qrCodeFromMachine) {
        if (StringUtils.isBlank(qrCodeFromMachine)) {
            MyException.throwError("data不能为空");
        }
        if (qrCodeFromMachine.length() != 40) {
            MyException.throwError("指令长度" + qrCodeFromMachine.length() + "不正确,长度应为:40");
        }
        var list = ByteUtil.hex2ByteList(qrCodeFromMachine);
//        if (!startByte.equals(list.get(0))){
        if (!qrCodeFromMachine.startsWith("55")) {
            MyException.throwErrorFillInStackTrace("指令应是55开头");
        }
        String sumNo_data = qrCodeFromMachine.substring(2, 38);
        String check_sumNo = byteUtils.Bytes2HexString(
                        byteUtils.getByteByBytesSum(
                                byteUtils.HexString2Bytes(sumNo_data), true))
                .toUpperCase();
        String machine_sumNo = qrCodeFromMachine.substring(38, 40);
        if (!check_sumNo.equals(machine_sumNo)) {
            MyException.throwErrorFillInStackTrace("qrCodeFromMachine 不符合数据规则!" + qrCodeFromMachine);
        }

        var machineId = qrCodeFromMachine.substring(2, 10);
        var unitCode = qrCodeFromMachine.substring(2, 6);
        /*工况：未启用*/
        var back = qrCodeFromMachine.substring(10, 12);
        /*充值时间*/
        var beforeTimeHex = qrCodeFromMachine.substring(12, 20);
        var beforeTimeBytes = list.subList(6, 10);
        /*需要解密的数据*/
        var desData = qrCodeFromMachine.substring(20, 36);
        /*硬件随机数*/
        var randomByte = list.get(18);
        var random = qrCodeFromMachine.substring(36, 38);

//        System.out.println("随机数："+randomByte);

        /*充值时间，精确到秒，可以转成时间戳*/
        var beforeTime = DateToHexStringUtil.HexStringTodate(beforeTimeHex);

//        var unKeyBytes1 = new ArrayList<>(beforeTimeBytes);
//        unKeyBytes1.add(Integer.valueOf(beforeTimeBytes.get(0) ^ 0XAA).byteValue());
//        unKeyBytes1.add(Integer.valueOf(beforeTimeBytes.get(1) ^ 0X55).byteValue());
//        unKeyBytes1.add(Integer.valueOf(beforeTimeBytes.get(2) ^ 0X55).byteValue());
//        unKeyBytes1.add(Integer.valueOf(beforeTimeBytes.get(3) ^ 0XAA).byteValue());
//        var unKey = ByteUtil.byteList2Hex(unKeyBytes1) + desData;
        var unKey = machineId + beforeTimeHex + random + "FFFFFFFFFFFFFF";
        String discryption_data = new DesHelperV2().PBOC_3DES_MAC_discryption(desData, unKey);
        var beforeUserIdHex = discryption_data.substring(0, 8);
        /*卡号:前6位*/
        var beforeCardId = discryption_data.substring(8, 14);

        /*F1表示上一笔充值有可能充值失败，F0表示充值成功*/
        var beforeResult = Integer.valueOf(discryption_data.substring(14, 16), 16);

        Map<String, Object> result = new HashMap<>();
        result.put("machineId", machineId);
        result.put("unitCode", unitCode);/*单位代码*/
        result.put("beforeTimeHex", beforeTimeHex);
        result.put("beforeTime", beforeTime);
        result.put("beforeUserIdHex", beforeUserIdHex);
        result.put("beforeCardId", beforeCardId);
        result.put("beforeResult", beforeResult);
        return result;
    }

    /*获取充值二维码*/
    public static String get(String qrCodeFromMachine, String machineId, String userIdHex, Long time, Integer num) {
        if (StringUtils.isBlank(qrCodeFromMachine)) {
            MyException.throwError("data不能为空");
        }
        if (StringUtils.isAnyBlank(machineId, userIdHex)) {
            MyException.throwError("machineId/userIdHex不能为空");
        }
        if (time == null) {
            time = System.currentTimeMillis();
        }
        if (num == null || num < 1 || num > 65535) {
            MyException.throwError("充值金额num异常:" + num);
        }
        userIdHex = fillPrefix(userIdHex, "0", 8);
        /*硬件随机数*/
        var list = ByteUtil.hex2ByteList(qrCodeFromMachine);
        var randomByte = list.get(18);
        var random = qrCodeFromMachine.substring(36, 38);
        var desData = qrCodeFromMachine.substring(20, 36);
//        APP二维码内容组成：15字节
//        55 + 4字节时间 + 8字节加密内容 + 1字节硬件随机数取反+ 1字节校验(从4字节时间开始到最后的累加和取反校验)
//        8字节加密内容：4字节电子账户+2字节充值金额 + +1字节版本号+ 1字节硬件随机数
        Long finalTime = time;
        var timeHex = DateToHexStringUtil.dateToHexString(TimeUtil.long2Str(time, TimeFormat.DEFAULT).orElseThrow(() -> MyException.error("time" + finalTime + "不是时间")));
        var systemdata_before = userIdHex + ByteUtil.int2Hex(num, 2, "") + "01" + random;
        var timeBytes = ByteUtil.hex2ByteList(timeHex);

        var unKeyBytes1 = new ArrayList<>(timeBytes);
        unKeyBytes1.add(Integer.valueOf(timeBytes.get(0) ^ 0XAA).byteValue());
        unKeyBytes1.add(Integer.valueOf(timeBytes.get(1) ^ 0X55).byteValue());
        unKeyBytes1.add(Integer.valueOf(timeBytes.get(2) ^ 0X55).byteValue());
        unKeyBytes1.add(Integer.valueOf(timeBytes.get(3) ^ 0XAA).byteValue());
        var unKey = ByteUtil.byteList2Hex(unKeyBytes1) + desData;
        System.out.println("加密key:" + unKey + ",明文:" + systemdata_before);
        String des_systemdata = new DesHelperV2().PBOC_3DES(systemdata_before, unKey, 0);
        var r = ByteUtil.byte2Hex(Integer.valueOf(~randomByte).byteValue());
//        var r=ByteUtil.byte2Hex(Integer.valueOf(randomByte).byteValue());
        var sumData = timeHex + systemdata_before + r;

        String check_sumNo = byteUtils.Bytes2HexString(
                        byteUtils.getByteByBytesSum(
                                byteUtils.HexString2Bytes(sumData), true))
                .toUpperCase();
        return "55" + timeHex + des_systemdata + r + check_sumNo;
    }

    /**
     * 文本的长度不够时，前缀填充指定字符串
     *
     * @param text
     * @param fill
     * @param length
     * @return
     */
    public static String fillPrefix(String text, String fill, int length) {
        if (text == null) {
            text = "";
        }
        return text.length() < length ? fill.repeat(length - text.length()).concat(text) : text;
    }
}
